#!/usr/bin/env script/runner

class MemoryProfiler
  DEFAULTS = {:delay => 100, :csv_class_report => false}
  
  def self.start(opt={})
    opt = DEFAULTS.dup.merge(opt)
    
    Thread.new do
      prev = Hash.new(0)
      curr = Hash.new(0)
      curr_strings = []
      delta = Hash.new(0)
      
      file = File.open('log/memory_profiler.log','w')
      if opt[:csv_class_report]
        overall_count_file = File.open('log/memory_profiler_overall.csv','w')
      end
      
      loop do
        begin
          GC.start
          curr.clear
          ObjectSpace.each_object do |o|
            if o.class
              curr[o.class] += 1
            end
          end
          if opt[:csv_class_report]
            timestamp = Time.now.to_i
            curr.each {|k,v|
              overall_count_file.printf "%s,%s,%s\n", timestamp, k.name, v
            }
          end
          
          delta.clear
           (curr.keys + delta.keys).uniq.each do |k,v|
            delta[k] = curr[k]-prev[k]
          end
          
          file.puts "Top 20"
          delta.sort_by { |k,v| -v.abs }[0..19].sort_by { |k,v| -v}.each do |k,v|
            file.printf "%+5d: %s (%d)\n", v, k.name, curr[k] unless v == 0
          end
          file.flush
          
          delta.clear
          prev.clear
          prev.update curr
          GC.start
        rescue Exception => err
          STDERR.puts "** memory_profiler error: #{err}"
        end
        sleep opt[:delay]
      end
    end
  end
end

require 'action_controller/integration'
require 'profiler'
app = ActionController::Integration::Session.new
MemoryProfiler.start(:delay => 1, :csv_class_report => false)
app.get ARGV[0].to_s
